package repository

import (
	"fmt"
	"time"

	"fitness/go-admin/internal/model"

	"gorm.io/gorm"
)

// FileRepository 文件仓储接口
type FileRepository interface {
	// 文件记录管理
	CreateFileRecord(file *model.FileRecord) error
	GetFileRecordByID(id uint) (*model.FileRecord, error)
	GetFileRecordByMD5(md5 string) (*model.FileRecord, error)
	UpdateFileRecord(file *model.FileRecord) error
	DeleteFileRecord(id uint) error
	GetFileRecordList(req *model.FileListReq) ([]model.FileRecord, int64, error)
	GetFileStatistics(uploaderID uint, uploaderType string) (*model.FileStatistics, error)
	BatchDeleteFiles(ids []uint) error

	// 训练照片管理
	CreateTrainingPhoto(photo *model.TrainingPhoto) error
	GetTrainingPhotoByID(id uint) (*model.TrainingPhoto, error)
	UpdateTrainingPhoto(photo *model.TrainingPhoto) error
	DeleteTrainingPhoto(id uint) error
	GetTrainingPhotoList(req *model.TrainingPhotoListReq) ([]model.TrainingPhoto, int64, error)
	GetMemberPhotoTimeline(memberID uint) ([]model.TrainingPhoto, error)

	// 教练证书管理
	CreateCoachCertificate(cert *model.CoachCertificate) error
	GetCoachCertificateByID(id uint) (*model.CoachCertificate, error)
	UpdateCoachCertificate(cert *model.CoachCertificate) error
	DeleteCoachCertificate(id uint) error
	GetCoachCertificateList(req *model.CertificateListReq) ([]model.CoachCertificate, int64, error)
	GetCoachCertificates(coachID uint) ([]model.CoachCertificate, error)
	VerifyCoachCertificate(id uint, isVerified bool, verifiedBy uint, remark string) error
}

// fileRepository 文件仓储实现
type fileRepository struct {
	db *gorm.DB
}

// NewFileRepository 创建文件仓储实例
func NewFileRepository(db *gorm.DB) FileRepository {
	return &fileRepository{db: db}
}

// ======================== 文件记录管理 ========================

// CreateFileRecord 创建文件记录
func (r *fileRepository) CreateFileRecord(file *model.FileRecord) error {
	return r.db.Create(file).Error
}

// GetFileRecordByID 根据ID获取文件记录
func (r *fileRepository) GetFileRecordByID(id uint) (*model.FileRecord, error) {
	var file model.FileRecord
	err := r.db.Where("id = ? AND status = ?", id, model.FileStatusNormal).First(&file).Error
	if err != nil {
		return nil, err
	}
	return &file, nil
}

// GetFileRecordByMD5 根据MD5获取文件记录（秒传功能）
func (r *fileRepository) GetFileRecordByMD5(md5 string) (*model.FileRecord, error) {
	var file model.FileRecord
	err := r.db.Where("md5 = ? AND status = ?", md5, model.FileStatusNormal).First(&file).Error
	if err != nil {
		return nil, err
	}
	return &file, nil
}

// UpdateFileRecord 更新文件记录
func (r *fileRepository) UpdateFileRecord(file *model.FileRecord) error {
	return r.db.Save(file).Error
}

// DeleteFileRecord 删除文件记录（软删除）
func (r *fileRepository) DeleteFileRecord(id uint) error {
	return r.db.Model(&model.FileRecord{}).
		Where("id = ?", id).
		Update("status", model.FileStatusDeleted).Error
}

// GetFileRecordList 获取文件记录列表
func (r *fileRepository) GetFileRecordList(req *model.FileListReq) ([]model.FileRecord, int64, error) {
	var files []model.FileRecord
	var total int64

	query := r.db.Model(&model.FileRecord{})

	// 条件筛选
	if req.FileType != "" {
		query = query.Where("file_type = ?", req.FileType)
	}
	if req.UploaderID > 0 {
		query = query.Where("uploader_id = ?", req.UploaderID)
	}
	if req.UploaderType != "" {
		query = query.Where("uploader_type = ?", req.UploaderType)
	}
	if req.Status != "" {
		query = query.Where("status = ?", req.Status)
	} else {
		query = query.Where("status = ?", model.FileStatusNormal)
	}

	// 日期范围
	if req.StartDate != "" {
		startDate, _ := time.Parse("2006-01-02", req.StartDate)
		query = query.Where("created_at >= ?", startDate)
	}
	if req.EndDate != "" {
		endDate, _ := time.Parse("2006-01-02", req.EndDate)
		endDate = endDate.Add(24 * time.Hour)
		query = query.Where("created_at < ?", endDate)
	}

	// 统计总数
	if err := query.Count(&total).Error; err != nil {
		return nil, 0, err
	}

	// 分页查询
	offset := (req.Page - 1) * req.PageSize
	err := query.Order("created_at DESC").
		Limit(req.PageSize).
		Offset(offset).
		Find(&files).Error

	return files, total, err
}

// GetFileStatistics 获取文件统计信息
func (r *fileRepository) GetFileStatistics(uploaderID uint, uploaderType string) (*model.FileStatistics, error) {
	stats := &model.FileStatistics{}

	query := r.db.Model(&model.FileRecord{}).Where("status = ?", model.FileStatusNormal)
	if uploaderID > 0 {
		query = query.Where("uploader_id = ?", uploaderID)
	}
	if uploaderType != "" {
		query = query.Where("uploader_type = ?", uploaderType)
	}

	// 总文件数和总大小
	if err := query.Count(&stats.TotalFiles).Error; err != nil {
		return nil, err
	}

	var totalSize int64
	if err := query.Select("COALESCE(SUM(file_size), 0)").Scan(&totalSize).Error; err != nil {
		return nil, err
	}
	stats.TotalSize = totalSize
	stats.TotalSizeStr = formatFileSize(totalSize)

	// 各类型文件数量
	type TypeCount struct {
		FileType string
		Count    int64
	}
	var typeCounts []TypeCount
	query.Select("file_type, COUNT(*) as count").
		Group("file_type").
		Scan(&typeCounts)

	for _, tc := range typeCounts {
		switch tc.FileType {
		case string(model.FileTypeAvatar):
			stats.AvatarCount = tc.Count
		case string(model.FileTypeCertificate):
			stats.CertificateCount = tc.Count
		case string(model.FileTypeTraining):
			stats.TrainingCount = tc.Count
		case string(model.FileTypeOther):
			stats.OtherCount = tc.Count
		}
	}

	return stats, nil
}

// BatchDeleteFiles 批量删除文件
func (r *fileRepository) BatchDeleteFiles(ids []uint) error {
	return r.db.Model(&model.FileRecord{}).
		Where("id IN ?", ids).
		Update("status", model.FileStatusDeleted).Error
}

// ======================== 训练照片管理 ========================

// CreateTrainingPhoto 创建训练照片
func (r *fileRepository) CreateTrainingPhoto(photo *model.TrainingPhoto) error {
	return r.db.Create(photo).Error
}

// GetTrainingPhotoByID 根据ID获取训练照片
func (r *fileRepository) GetTrainingPhotoByID(id uint) (*model.TrainingPhoto, error) {
	var photo model.TrainingPhoto
	err := r.db.Preload("Member").Preload("File").First(&photo, id).Error
	if err != nil {
		return nil, err
	}
	return &photo, nil
}

// UpdateTrainingPhoto 更新训练照片
func (r *fileRepository) UpdateTrainingPhoto(photo *model.TrainingPhoto) error {
	return r.db.Save(photo).Error
}

// DeleteTrainingPhoto 删除训练照片
func (r *fileRepository) DeleteTrainingPhoto(id uint) error {
	return r.db.Delete(&model.TrainingPhoto{}, id).Error
}

// GetTrainingPhotoList 获取训练照片列表
func (r *fileRepository) GetTrainingPhotoList(req *model.TrainingPhotoListReq) ([]model.TrainingPhoto, int64, error) {
	var photos []model.TrainingPhoto
	var total int64

	query := r.db.Model(&model.TrainingPhoto{})

	// 条件筛选
	if req.MemberID > 0 {
		query = query.Where("member_id = ?", req.MemberID)
	}
	if req.PhotoType != "" {
		query = query.Where("photo_type = ?", req.PhotoType)
	}
	if req.IsPublic != nil {
		query = query.Where("is_public = ?", *req.IsPublic)
	}

	// 日期范围
	if req.StartDate != "" {
		startDate, _ := time.Parse("2006-01-02", req.StartDate)
		query = query.Where("training_date >= ?", startDate)
	}
	if req.EndDate != "" {
		endDate, _ := time.Parse("2006-01-02", req.EndDate)
		query = query.Where("training_date <= ?", endDate)
	}

	// 统计总数
	if err := query.Count(&total).Error; err != nil {
		return nil, 0, err
	}

	// 分页查询
	offset := (req.Page - 1) * req.PageSize
	err := query.Preload("Member").Preload("File").
		Order("training_date DESC, created_at DESC").
		Limit(req.PageSize).
		Offset(offset).
		Find(&photos).Error

	return photos, total, err
}

// GetMemberPhotoTimeline 获取会员照片时间线
func (r *fileRepository) GetMemberPhotoTimeline(memberID uint) ([]model.TrainingPhoto, error) {
	var photos []model.TrainingPhoto
	err := r.db.Where("member_id = ?", memberID).
		Preload("File").
		Order("training_date ASC, created_at ASC").
		Find(&photos).Error
	return photos, err
}

// ======================== 教练证书管理 ========================

// CreateCoachCertificate 创建教练证书
func (r *fileRepository) CreateCoachCertificate(cert *model.CoachCertificate) error {
	return r.db.Create(cert).Error
}

// GetCoachCertificateByID 根据ID获取教练证书
func (r *fileRepository) GetCoachCertificateByID(id uint) (*model.CoachCertificate, error) {
	var cert model.CoachCertificate
	err := r.db.Preload("Coach").Preload("File").First(&cert, id).Error
	if err != nil {
		return nil, err
	}
	return &cert, nil
}

// UpdateCoachCertificate 更新教练证书
func (r *fileRepository) UpdateCoachCertificate(cert *model.CoachCertificate) error {
	return r.db.Save(cert).Error
}

// DeleteCoachCertificate 删除教练证书
func (r *fileRepository) DeleteCoachCertificate(id uint) error {
	return r.db.Delete(&model.CoachCertificate{}, id).Error
}

// GetCoachCertificateList 获取教练证书列表
func (r *fileRepository) GetCoachCertificateList(req *model.CertificateListReq) ([]model.CoachCertificate, int64, error) {
	var certs []model.CoachCertificate
	var total int64

	query := r.db.Model(&model.CoachCertificate{})

	// 条件筛选
	if req.CoachID > 0 {
		query = query.Where("coach_id = ?", req.CoachID)
	}
	if req.IsVerified != nil {
		query = query.Where("is_verified = ?", *req.IsVerified)
	}

	// 统计总数
	if err := query.Count(&total).Error; err != nil {
		return nil, 0, err
	}

	// 分页查询
	offset := (req.Page - 1) * req.PageSize
	err := query.Preload("Coach").Preload("File").
		Order("created_at DESC").
		Limit(req.PageSize).
		Offset(offset).
		Find(&certs).Error

	return certs, total, err
}

// GetCoachCertificates 获取教练的所有证书
func (r *fileRepository) GetCoachCertificates(coachID uint) ([]model.CoachCertificate, error) {
	var certs []model.CoachCertificate
	err := r.db.Where("coach_id = ?", coachID).
		Preload("File").
		Order("created_at DESC").
		Find(&certs).Error
	return certs, err
}

// VerifyCoachCertificate 验证教练证书
func (r *fileRepository) VerifyCoachCertificate(id uint, isVerified bool, verifiedBy uint, remark string) error {
	now := time.Now()
	updates := map[string]interface{}{
		"is_verified": isVerified,
		"verified_at": &now,
		"verified_by": verifiedBy,
	}
	if remark != "" {
		updates["remark"] = remark
	}

	return r.db.Model(&model.CoachCertificate{}).
		Where("id = ?", id).
		Updates(updates).Error
}

// ======================== 工具函数 ========================

// formatFileSize 格式化文件大小
func formatFileSize(size int64) string {
	const unit = 1024
	if size < unit {
		return fmt.Sprintf("%d B", size)
	}
	div, exp := int64(unit), 0
	for n := size / unit; n >= unit; n /= unit {
		div *= unit
		exp++
	}
	return fmt.Sprintf("%.2f %cB", float64(size)/float64(div), "KMGTPE"[exp])
}
